import { log } from './log'

// We want to only ever create the API once, therefore we define a module-level
// singleton that holds the promise to create the API.
// As promises can be awaited any number of times in JavaScript, this gives us
// an async singleton instance to the wasm API.
const api = importAndInitOnce()

export async function initApi() {
  return await api
}

async function importAndInitOnce() {
  try {
    log.info('Importing WASM module')
    const { IrohAPI } = await import('./iroh')
    return await IrohAPI.create()
  } catch (err) {
    log.error('Failed to import or launch iroh', err)
    throw err
  }
}

export interface API {
  createChannel(nickname: string): Promise<ChannelInfo>
  joinChannel(ticket: string, nickname: string): Promise<ChannelInfo>
  sendMessage(channelId: string, message: string): void
  setNickname(channelId: string, nickname: string): void
  getMessages(channelId: string): Message[]
  getPeers(channelId: string): PeerInfo[]
  getMyself(channelId: string): PeerInfo
  subscribeToMessages(channelId: string, callback: (message: Message) => void): () => void
  subscribeToPeers(channelId: string, callback: () => void): () => void
  subscribeToNeighbors(channelId: string, callback: (neighbors: number) => void): () => void
  getTicket(channelId: string, opts: TicketOpts): string
  closeChannel(channelId: string): Promise<void>
  getChannel(channelId: string): any // Access to underlying WASM channel for advanced operations
  // Terminal management methods
  createTerminal(channelId: string, sessionId: string, shellPath?: string): Promise<void>
  sendTerminalInput(channelId: string, sessionId: string, data: Uint8Array): Promise<void>
  resizeTerminal(channelId: string, sessionId: string, rows: number, cols: number): Promise<void>
  closeTerminal(channelId: string, sessionId: string): Promise<void>
  renameTerminal(channelId: string, sessionId: string, newName?: string): Promise<void>  // Rename a terminal session (set or remove alias)
  subscribeToTerminalOutput(
    channelId: string,
    callback: (output: TerminalOutput) => void
  ): () => void
  subscribeToTerminalStatus(
    channelId: string,
    callback: (status: TerminalStatus) => void
  ): () => void
  subscribeToTerminalRename(
    channelId: string,
    callback: (rename: TerminalRename) => void
  ): () => void  // Subscribe to terminal rename events
  // Terminal synchronization methods
  sendTerminalSyncRequest(channelId: string, requesterId: string): Promise<void>
  sendTerminalSyncResponse(channelId: string, requesterId: string, terminals: TerminalInfo[]): Promise<void>
  sendTerminalSync(channelId: string, terminals: TerminalInfo[]): Promise<void>
  subscribeToTerminalSync(
    channelId: string,
    callback: (syncMessage: TerminalSyncMessage) => void
  ): () => void
  subscribeToTerminalState(
    channelId: string,
    callback: (stateMessage: TerminalStateMessage) => void
  ): () => void
}

export type SubscribeCb = (message: Message) => void

export type ChannelInfo = {
  id: string
  name: string
}

export type TicketOpts = {
  includeMyself: boolean
  includeBootstrap: boolean
  includeNeighbors: boolean
}

export interface Message {
  id: string
  sender: string
  content: string
  nickname?: string
}

export interface PeerInfo {
  id: string
  name: string
  status: 'online' | 'away' | 'offline'
  lastSeen: Date
  role: PeerRole
}

export interface TerminalOutput {
  sessionId: string
  data: Uint8Array
  timestamp: Date
}

export interface TerminalStatus {
  sessionId: string
  status: string
  timestamp: Date
}

export interface TerminalRename {
  sessionId: string
  newName?: string
  timestamp: Date
}

export interface TerminalInfo {
  sessionId: string
  name?: string
  position: { x: number; y: number }
  size: { rows: number; cols: number }
  status: 'active' | 'inactive' | 'closed'
  createdAt: Date
  lastActivity: Date
}

export interface TerminalSyncMessage {
  type: 'terminal_list_request' | 'terminal_list_response' | 'terminal_sync'
  requesterId: string
  terminals: TerminalInfo[]
  timestamp: Date
}

// Terminal state synchronization message - optimized version for sync_state_optimized
export interface TerminalStateMessage {
  type: 'terminal_state'
  from: string
  terminals: TerminalInfo[]
  timestamp: Date
}

// Terminal sync request message that matches the backend protocol
export interface TerminalSyncRequest {
  type: 'terminal_sync_request'
  requesterId: string
  timestamp: Date
}

// Terminal list response message
export interface TerminalListResponse {
  type: 'terminal_list_response'
  requesterId: string
  terminals: TerminalInfo[]
  timestamp: Date
}

export enum PeerRole {
  Myself,
  RemoteNode,
}
